package com.example.springbootthreaddemo;

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

public class verificate {

    //非对称密钥算法
    public static final String KEY_ALGORITHM = "RSA";

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /**
     * Map key 排序
     * @param map
     * @return
     */
    public static Map<String,String> order(Map<String, String> map){
        HashMap<String, String> tempMap = new LinkedHashMap<String, String>();
        List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(	map.entrySet());

        Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
            public int compare(Map.Entry<String, String> o1,Map.Entry<String, String> o2) {
                return (o1.getKey()).toString().compareTo(o2.getKey());
            }
        });
        for (int i = 0; i < infoIds.size(); i++) {
            Map.Entry<String, String> item = infoIds.get(i);
            tempMap.put(item.getKey(), item.getValue());
        }
        return tempMap;
    }

    /**
     * url 参数串连
     * @param map
     * @param separator 分隔符 默认为&
     * @param keyLower 是否发转成小写 true:转小写
     * @param valueUrlencode 是否编码 true:编码
     * @return
     */
    public static String mapJoin(Map<String, String> map, String separator, String valueSeparator,boolean keyLower,boolean valueUrlencode){
        StringBuilder stringBuilder = new StringBuilder();
        for(String key :map.keySet()){
            if(map.get(key)!=null&&!"".equals(map.get(key))){
                try {
                    String temp = (key.endsWith("_")&&key.length()>1)?key.substring(0,key.length()-1):key;
                    stringBuilder.append(keyLower?temp.toLowerCase():temp)
                            .append(valueSeparator==null?"=":valueSeparator)
                            .append(valueUrlencode? URLEncoder.encode(map.get(key),"utf-8").replace("+", "%20"):map.get(key))
                            .append(separator == null?"&":separator);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        if(stringBuilder.length()>0){
            stringBuilder.deleteCharAt(stringBuilder.length()-1);
        }
        return stringBuilder.toString();
    }

    /**
     * 公钥加密
     *
     * @param data 待加密数据
     * @param key       密钥
     * @return byte[] 加密数据
     */
    public static String encryptByPublicKey(String data, String key) throws Exception {
        byte[] keyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(key);
        byte[] dataBytes = data.getBytes("UTF-8");
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return Base64.encodeBase64String(encryptedData);
    }

    public static void main(String[] args) throws Exception{

        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("idCard","11010119900101055X");  //测试为随机生成
        map.put("name","测试");
        map.put("mobile","13800001111");
        map.put("id","000000000125");
        map.put("timestamp",String.valueOf(System.currentTimeMillis()));
        map.put("partnerId","12345678");
        map.put("appId","9095d7c04a16442886598b1ec45250cd");
        map.put("channelCode","mingda_jingji");
        //排序
        map = order(map);
        //转化为字符串
        String str = mapJoin(map, null, null, false, false);
        System.out.println(str);

//        str = "appId=12d5eeb377cf90079540f95889b34e&channelCode=woyunbao&id=897654356789098765431&idCard=440xxxxxxxxxxxxxxxx&mobile=13800001111&name=测试用户&partnerId=12345678&timestamp=1543312253";
        //公钥
        String publicKey = " MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbFeDw49rCEVWYttWQf9grQMFrMk3I4GAlECMJpmFCBpJjnVr/xBe3V7T0e29HARk136jGAk4II+jwFXIrsSr5UAwdbUNxIyZLPGOVyAsNz156om5K5JPmeKt85+5X8wKrBuuxsvHWG74DX9Ce4GaoSyCY7lFs1FS7Uj/jhVUiQIDAQAB";

        //加密
        String encryStr = encryptByPublicKey(str, publicKey);
        System.out.println(encryStr);
    }
}